﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Service.Model;

namespace Ebt.Linq
{
	/// <summary>
	/// Implements an <see cref="ExpressionVisitor"/> that searches for equality statements <c>property == value</c> in expression trees.
	/// </summary>
    public class FederationExpressionVisitor<TEntity> : ExpressionVisitor
	{
		private IDictionary<string, PropertyValue> _propertyValues;
        
		/// <summary>
		/// Walks through the expression tree.
		/// </summary>
		/// <param name="expression"></param>
		/// <returns>Equality statements.</returns>
		public IDictionary<string, PropertyValue> Translate(Expression expression)
		{
            _propertyValues = new Dictionary<string, PropertyValue>();
			Visit(expression);
			return _propertyValues;
		}
		
		protected override Expression VisitBinary(BinaryExpression b)
		{
            CollectEquality(b);

			return base.VisitBinary(b);
		}

        private void CollectEquality(BinaryExpression b)
	    {
            if (b.NodeType != ExpressionType.Equal)
                return;

            MemberExpression memberExp;
            ConstantExpression constExp;
            PropertyInfo propertyInfo;
            if ((memberExp = b.Left as MemberExpression) != null &&
                (propertyInfo = memberExp.Member as PropertyInfo) != null &&
                (propertyInfo.DeclaringType == typeof(TEntity)) &&
                (constExp = b.Right as ConstantExpression) != null)
            {
                try
                {
                    _propertyValues.Add(propertyInfo.Name, new PropertyValue {Property = propertyInfo, Value = constExp});
                }
                catch (ArgumentException)
                {
                    throw new Exception("Multiple federation distribution keys are not allowed.");
                }
            }
	    }
	}
}